import { Node, Edge } from '@antv/x6'
import { canvas, bgCanvas, dnd } from './canvasInstance'
import { storeToRefs } from 'pinia'
import { useCanvasParameterStore } from './canvasParameter'
import {
  renderDeleteEdge,
  renderDeleteNode,
  renderEdgeConnect,
  renderNodeBulkEdit,
  renderNodeMove,
  renderNodeTransform,
  renderShowCanvasProperty,
  renderShowEdgeProperty,
  renderShowNodeProperty
} from './mainProcessData'
import { useMessageStore } from '../message/message'
import {
  addEdgeTool,
  addFreeEditCircle,
  changeCanvasMode,
  closeCanvasTools,
  closeEdgeMove,
  finishEdgeEdit,
  freeAreaNodeMoveEnd,
  isCanvasClick,
  openEdgeMove,
  pasteNode,
  setPortVisible,
  showVertex,
  specialEdgeClick,
  updateVertex
} from './otherFun'
import { useCanvasSearchStore } from './canvasSearch'
import {
  forbiddenClickEdgeShape,
  forbiddenSelectNodeShape,
  moveShieldNodeShape
} from './canvasConst'
import { useStyleStore } from '../globalStyle/style'

//画布移动的消息是否禁止
let prohibitCanvasMoveMsg = false

//框选的节点
let frameSelectNodeIds = [] as string[]
//框选防抖的时间戳
let antiShake = null as any

//节点改变大小时，临时记录原有尺寸消息
const temNodeSize = {} as { id: string; width: number; height: number }
//节点移动时，临时记录
let temNodesPosition = [] as { id: string; x: number; y: number }[]

//画布监听事件
export const initCanvasEvents = (): void => {
  //判断canvas是否是空对象
  if (Object.keys(canvas).length === 0) {
    return
  }

  // 键盘 --> backspace删除节点
  canvas.bindKey(['backspace', 'delete'], () => {
    const { selectedNode, selectedEdge } = storeToRefs(useCanvasParameterStore())
    //删除单个节点
    if (selectedNode.value?.id) {
      renderDeleteNode(selectedNode.value?.id)
      selectedNode.value = null
      return
    }
    //删除单个边
    if (selectedEdge.value?.id) {
      renderDeleteEdge(selectedEdge.value?.id)
      selectedEdge.value = null
      return
    }
    //删除框选的节点
    if (canvas.getSelectedCellCount() > 0) {
      const ids = canvas.getSelectedCells().map((item) => item.id)
      renderDeleteNode(ids)
    }
  })

  //画布-启用搜索框
  canvas.bindKey(['ctrl+f'], () => {
    useCanvasSearchStore().switchSearchBox()
  })

  //画布-全屏
  canvas.bindKey(['shift+f'], () => {
    const { resourceRef, messageRef, attributeRef } = useStyleStore()

    if (resourceRef.getSize() === 0 && messageRef.getSize() === 0 && attributeRef.getSize() === 0) {
      useStyleStore().resizeAttribute(15)
      useStyleStore().resizeMessage(15)
      useStyleStore().resizeResource(13)
    } else {
      useStyleStore().resizeAttribute(0)
      useStyleStore().resizeMessage(0)
      useStyleStore().resizeResource(0)
    }
  })

  //画布-复制节点
  canvas.bindKey(['ctrl+c'], () => {
    const { selectedNode, copyNodeList } = storeToRefs(useCanvasParameterStore())
    copyNodeList.value = []

    if (selectedNode.value?.id) {
      copyNodeList.value = [selectedNode.value.id]
    } else {
      const selectNodes = canvas.getSelectedCells()
      selectNodes.forEach((item) => {
        if (canvas.isNode(item)) {
          copyNodeList.value.push(item.id)
        }
      })
    }
  })

  //画布-粘贴节点
  canvas.bindKey(['ctrl+v'], () => {
    pasteNode()
  })

  //画布-撤销
  canvas.bindKey(['ctrl+z'], () => {
    window.api.handleCanvasData('readHistory', 'canvas2D', false, [])
  })

  //画布-缩放事件
  canvas.on('scale', () => {
    //获取canvas的缩放级别
    const zoom = canvas.zoom()
    bgCanvas.zoom(zoom, { absolute: true })
    const { canvasScale } = storeToRefs(useCanvasParameterStore())
    canvasScale.value = zoom

    //给画布操作发消息
    useMessageStore().addCanvasOperate({
      source: '画布缩放',
      content: `当前缩放比例`,
      otherMsg: zoom.toFixed(2)
    })
    prohibitCanvasMoveMsg = false
  })

  //画布-移动事件
  canvas.on('translate', ({ tx, ty }: { tx: number; ty: number }) => {
    const { canvasPosition } = storeToRefs(useCanvasParameterStore())
    canvasPosition.value.x = -tx
    canvasPosition.value.y = -ty

    bgCanvas.translate(tx, ty)
    if (prohibitCanvasMoveMsg) {
      //给画布操作发消息
      useMessageStore().addCanvasOperate({
        source: '画布移动',
        content: `当前画布位置`,
        otherMsg: `x：${-tx.toFixed(2)}，y：${-ty.toFixed(2)}`
      })
    } else {
      prohibitCanvasMoveMsg = true
    }
  })

  //画布-点击事件
  canvas.on('blank:click', () => {
    if (isCanvasClick()) return
    //打开画布属性面板
    renderShowCanvasProperty()
    window.api.handleCanvasData('selectNodesOrEdges', 'canvas2D', true, [[]])

    //关闭一些工具
    closeCanvasTools()
  })

  //节点-自定义点击事件
  canvas.on('node:customevent', ({ name, node }: { name: string; node: Node }) => {
    if (name === 'customPortNodeClick') {
      renderShowNodeProperty(node, 'freeEdit')
    } else if (name === 'textNodeClick') {
      renderShowNodeProperty(node, 'plaintext')
    }
  })

  //节点-双击事件
  canvas.on('node:dblclick', ({ node }: { node: Node }) => {
    if (node.shape === 'custom-port-node') {
      showVertex(node)
    }

    if (node.shape === 'ordinary-node') {
      const { isGraphTransform } = storeToRefs(useCanvasParameterStore())
      isGraphTransform.value = true
      canvas.createTransformWidget(node)
      const { width, height } = node.getSize()
      temNodeSize.id = node.id
      temNodeSize.width = width
      temNodeSize.height = height
      setTimeout(() => {
        const { isGraphTransform } = storeToRefs(useCanvasParameterStore())
        isGraphTransform.value = false
      }, 300)
    }
  })

  //节点-尺寸改变中
  canvas.on('node:resizing', ({ node }: { node: Node }) => {
    const { width, height } = node.size()
    renderNodeTransform(node.id, width, height)
    //给画布操作发消息
    useMessageStore().addCanvasOperate({
      source: '节点变换',
      content: `${node.getData()?.name}`,
      otherMsg: `w：${width.toFixed(2)}，h：${height.toFixed(2)}`
    })
  })

  //节点-尺寸改变结束
  canvas.on('node:resized', ({ node }: { node: Node }) => {
    if (temNodeSize.id === node.id && temNodeSize.width && temNodeSize.height) {
      window.api.handleCanvasData('changeNodeSizeRecord', 'canvas2D', false, [[temNodeSize]])
      temNodeSize.id = ''
    }
  })

  //节点-移动开始事件
  canvas.on('node:move', ({ node }: { node: Node }) => {
    //移动需要屏蔽的节点
    if (moveShieldNodeShape.includes(node.shape)) return

    const { x, y } = node.position()
    temNodesPosition.push({
      id: node.id,
      x,
      y
    })
  })

  // 节点-移动过程中事件
  canvas.on('node:moving', ({ node }: { node: Node }) => {
    //移动需要屏蔽的节点
    if (moveShieldNodeShape.includes(node.shape)) return

    if (canvas.getSelectedCellCount() > 1) {
      return
    }
    const { x, y } = node.position()
    renderNodeMove(node.id, x, y)
    //给画布操作发消息
    useMessageStore().addCanvasOperate({
      source: '节点移动',
      content: `${node.getData()?.name}`,
      otherMsg: `x：${x.toFixed(2)}，y：${y.toFixed(2)}`
    })
  })

  // 节点-移动结束事件
  canvas.on('node:moved', ({ node }: { node: Node }) => {
    if (node.shape === 'free-edit-circle') {
      updateVertex(node)
      return
    }

    if (canvas.getSelectedCellCount() > 1) {
      const nodes = canvas.getSelectedCells() as Node[]
      nodes.forEach((item) => {
        const { x, y } = item.getPosition()
        renderNodeMove(item.id, x, y)
      })
    }

    if (temNodesPosition.length === 0) return
    window.api.handleCanvasData('moveNodeRecord', 'canvas2D', false, [temNodesPosition])
    temNodesPosition = []

    //如果被移动的节点是自由编辑区域，且正处于编辑的状态
    if (node.shape === 'custom-port-node') {
      freeAreaNodeMoveEnd(node)
    }
  })

  // 节点-框选-选中事件
  canvas.on('node:selected', ({ node }: { node: Node }) => {
    if (forbiddenSelectNodeShape.includes(node.shape)) return

    const { isCanvasSelect } = storeToRefs(useCanvasParameterStore())
    if (!isCanvasSelect.value) {
      return
    }

    //在这里加一个防抖机制
    frameSelectNodeIds.push(node.id)
    canvas.cleanSelection()
    clearTimeout(antiShake)
    antiShake = setTimeout(() => {
      window.api.handleCanvasData('selectNodesOrEdges', 'canvas2D', true, [frameSelectNodeIds])
      if (frameSelectNodeIds.length > 1) {
        renderNodeBulkEdit()
      }
      frameSelectNodeIds = []
    }, 50)
  })

  //边-连接事件
  canvas.on('edge:connected', ({ edge }: { edge: Edge }) => {
    renderEdgeConnect(edge)
  })

  //边-点击事件
  canvas.on('edge:click', ({ e, edge, view }) => {
    if (forbiddenClickEdgeShape.includes(edge.shape)) return

    renderShowEdgeProperty(edge)
    window.api.handleCanvasData('selectNodesOrEdges', 'canvas2D', true, [[edge.id]])
  })

  //边-自定义点击事件
  canvas.on('edge:customevent', ({ name, e, edge, x, y }) => {
    if (name === 'conveyorClick') {
      //特殊边处理
      specialEdgeClick(edge)
    }
    if (name === 'freeEditEdgeClick') {
      e.stopPropagation()
      addFreeEditCircle(edge, x, y)
    }
    if (name === 'roadEdgeClick') {
      console.log('object')
    }
  })

  //边-双击事件
  canvas.on('edge:dblclick', ({ edge }) => {
    addEdgeTool(edge)
    const { selectedEdge } = storeToRefs(useCanvasParameterStore())
    selectedEdge.value = edge
  })

  //边-进入事件
  canvas.on('edge:mouseenter', ({ edge }) => {
    //开启边移动
    openEdgeMove(edge)
  })

  //边-移出事件
  canvas.on('edge:mouseleave', ({ edge }) => {
    //关闭边移动
    closeEdgeMove(edge)
  })

  //边-移动结束
  canvas.on('edge:moved', ({ edge }: { edge: Edge }) => {
    const { isEdgeEdit } = storeToRefs(useCanvasParameterStore())
    if (!isEdgeEdit.value) {
      finishEdgeEdit()
    }
  })
}

//工具箱-节点拖拽事件
export const initToolBoxDragEvents = (e: MouseEvent, item: any): void => {
  if (item.type === 'belt') {
    const node = canvas.createNode({
      shape: 'edge-drag-node',
      attrs: {
        label: {
          text: '传送带'
        }
      },
      data: {
        name: '传送带',
        shape: 'conveyor-belt'
      }
    })
    dnd.start(node, e)
    return
  } else if (item.type === 'road') {
    const node = canvas.createNode({
      shape: 'edge-drag-node',
      attrs: {
        label: {
          text: '道路'
        }
      },
      data: {
        name: '道路',
        shape: 'road-edge'
      }
    })
    dnd.start(node, e)
    return
  } else if (item.type === 'warningLine') {
    const node = canvas.createNode({
      shape: 'edge-drag-node',
      attrs: {
        label: {
          text: '警戒线'
        }
      },
      data: {
        name: '警戒线',
        shape: 'warning-line'
      }
    })
    dnd.start(node, e)
    return
  } else if (item.type === 'customArea') {
    const node = canvas.createNode({
      shape: 'custom-port-node',
      data: {
        name: item.name,
        type: item.type,
        icon: item.icon
      }
    })
    dnd.start(node, e)
    return
  } else if (item.type === 'AGV') {
    const node = canvas.createNode({
      shape: 'transport-node',
      data: {
        name: item.name,
        type: item.type,
        icon: item.icon
      }
    })
    dnd.start(node, e)
    return
  } else if (item.type === 'crossing') {
    const node = canvas.createNode({
      shape: 'cross-node',
      data: {
        name: item.name,
        type: item.type,
        icon: item.icon
      }
    })
    dnd.start(node, e)
    return
  } else if (item.type === 'plaintext') {
    const node = canvas.createNode({
      shape: 'text-node',
      data: {
        name: item.name,
        type: item.type,
        icon: item.icon
      }
    })
    dnd.start(node, e)
    return
  }
  const node = canvas.createNode({
    shape: 'ordinary-node',
    data: {
      name: item.name,
      type: item.type,
      icon: item.icon
    }
  })
  dnd.start(node, e)
}

//键盘按下
export const spaceKeyDownEvents = (e: KeyboardEvent): void => {
  //如果是空格键
  if (e.code === 'Space') {
    const { canvasMode } = storeToRefs(useCanvasParameterStore())
    canvasMode.value.before = 'select'
    if (canvasMode.value.current === 'select') {
      changeCanvasMode('drag')
    }
  }

  //禁用滑轮
  canvas.disableMouseWheel()

  //shift+e
  if (e.code === 'KeyE' && e.shiftKey) {
    const { isShiftEDown } = storeToRefs(useCanvasParameterStore())
    isShiftEDown.value = true
    return
  }

  //sfit+r
  if (e.code === 'KeyR' && e.shiftKey) {
    const { isShiftRDown } = storeToRefs(useCanvasParameterStore())
    isShiftRDown.value = true
    return
  }

  //shift
  if (e.code === 'ShiftLeft' || e.code === 'ShiftRight') {
    const { isShiftDown } = storeToRefs(useCanvasParameterStore())
    isShiftDown.value = true
    return
  }
  //ctrl
  if (e.code === 'ControlLeft' || e.code === 'ControlRight') {
    const { isCtrlDown } = storeToRefs(useCanvasParameterStore())
    isCtrlDown.value = true
    return
  }
}

//键盘松开
export const spaceKeyUpEvents = (e: KeyboardEvent): void => {
  //如果是空格键
  if (e.code === 'Space') {
    changeCanvasMode('before')
  }

  //启用滑轮
  canvas.enableMouseWheel()

  //如果是shift+e,但是检测的灵敏度不高，所以只检测e键松开
  if (e.code === 'KeyE') {
    const { isShiftEDown } = storeToRefs(useCanvasParameterStore())
    isShiftEDown.value = false
    return
  }

  //如果是shift+r,但是检测的灵敏度不高，所以只检测r键松开
  if (e.code === 'KeyR') {
    const { isShiftRDown } = storeToRefs(useCanvasParameterStore())
    isShiftRDown.value = false
    return
  }

  //如果是shift
  if (e.code === 'ShiftLeft' || e.code === 'ShiftRight') {
    const { isShiftDown } = storeToRefs(useCanvasParameterStore())
    isShiftDown.value = false
  }
  //如果是ctrl
  if (e.code === 'ControlLeft' || e.code === 'ControlRight') {
    const { isCtrlDown } = storeToRefs(useCanvasParameterStore())
    isCtrlDown.value = false
  }
}

//鼠标-滑轮事件
export const mouseWheelEvents = (e: WheelEvent): void => {
  const { canvasScale, isShiftDown, isCtrlDown } = storeToRefs(useCanvasParameterStore())

  let move = 30 / canvasScale.value
  if (move > 100) {
    move = 100
  }
  const { tx: oldX, ty: oldY } = canvas.translate()
  if (e.deltaY < 0) {
    if (isShiftDown.value) {
      const x = oldX + move
      canvas.translate(x, oldY)
    } else if (isCtrlDown.value) {
      const y = oldY + move
      canvas.translate(oldX, y)
    }
  } else {
    if (isShiftDown.value) {
      const x = oldX - move
      canvas.translate(x, oldY)
    } else if (isCtrlDown.value) {
      const y = oldY - move
      canvas.translate(oldX, y)
    }
  }
}
